# _*_coding:utf-8_*_
'''
Created on Mar 5, 2014
This class is for NI PXI2534 matrix(8x32). All functions are from the control dll ni-swtich.dll.
@author: JZHAI
'''
import ctypes
import pyvisa.ctwrapper as vitypes
from ATS.errHandler import errHandler
from ATS.instrumentDriver import InstGen
from ATS.instrumentDriver import InstConstant as const
try:
    switch_dll = ctypes.windll.LoadLibrary("niswitch_32.dll")
except:
    switch_dll = None


class MTRX_NI(InstGen.MTRX):
    def __init__(self, name, info_dict):
        InstGen.MTRX.__init__(self, name, info_dict)
        self.handler = None

    def __gethandler(self):
        if self.handler is None:
            self.handler = self.Init()
        return self.handler

    def __del(self):
        self.Close()

    def __posterr(self, msg):
        who = "InstGen.MTRX.MTRX_NI"
        err_code = 30100
        errHandler.handle_err(who, err_code, msg)

    def Init(self, resetDevice=False):
        """
        ViStatus niSwitch_InitWithTopology (ViRsrc resourceName, ViConstString topology, ViBoolean simulate, ViBoolean resetDevice, ViSession* vi);
        resourceName: Always use "Dev#" as resouce name, which can be assigned in NIMax.
        """
        global switch_dll
        if not switch_dll:
            msg = "Cannot initialize switch_dll, because cannot find out 'niswitch_32.dll'."
            self.__posterr(msg)
            return None
        dev_id = self.info_dict.get("dev_num", 1)
        # rsrc_name = vitypes.ViRsrc("PXI%d::%s"%(pxi_bus,dev_id))
        rsrc_name = vitypes.ViRsrc("Dev%d" % dev_id)
        topology = self.info_dict["topology"]
        topology = vitypes.ViString(topology)
        # print "topology",topology
        simulate = self.info_dict.get("simulate", 0)
        simulate = vitypes.ViBoolean(simulate)
        resetDevice = vitypes.ViBoolean(resetDevice)
        session = vitypes.ViSession()
        status = switch_dll.niSwitch_InitWithTopology(rsrc_name, topology, simulate, resetDevice, ctypes.byref(session))
        # print "niSwitch_InitWithTopology status", status
        if status != 0:
            self.__posterr("Init() function: niSwitch_InitWithTopology execute failed. Error Code =" + str(hex(status)))
        return session

    def GetError(self, err_code):
        """
        ViStatus niSwitch_error_message (ViSession vi, ViStatus errorCode, ViChar[] errorMessage);
        """
        global switch_dll
        errorCode = vitypes.ViStatus(err_code)
        errorString = ctypes.create_string_buffer("", 1000)
        handler = self.__gethandler()
        stat = switch_dll.niSwitch_GetError(handler, errorCode, ctypes.byref(errorString))
        # print "GetErrorString stat", stat
        return repr(errorString.value)

    def RelayControl(self, relayName, relayAction):
        """
        ViStatus niSwitch_RelayControl (ViSession vi, ViConstString relayName, ViInt32 relayAction);
        relayName: "kr0c1", refer to section Devices in NI Switches Help for valid channel names for the switch module.
        relayAction: 0=Open, 1=Close
        """
        global switch_dll
        relayName = vitypes.ViString(relayName)
        act = {"0": const.NISWITCH_VAL_OPEN_RELAY, "1": const.NISWITCH_VAL_CLOSE_RELAY}
        relayAction = act.get(str(relayAction), const.NISWITCH_VAL_OPEN_RELAY)
        relayAction = vitypes.ViInt32(relayAction)
        handler = self.__gethandler()
        status = switch_dll.niSwitch_RelayControl(handler, relayName, relayAction)
        if status != 0:
            err_str = self.GetError(status)
            self.__posterr("RelayControl() function. " + err_str)
        return status

    def Connect(self, con_str1, con_str2):
        """
        ViStatus niSwitch_Connect (ViSession vi, ViConstString channel1, ViConstString channel2);
        con_str1: r0~r7
        con_str2: c0~c31
        """
        global switch_dll
        channel1 = vitypes.ViString(con_str1)
        channel2 = vitypes.ViString(con_str2)
        handler = self.__gethandler()
        status = switch_dll.niSwitch_Connect(handler, channel1, channel2)
        if status != 0:
            err_str = self.GetError(status)
            self.__posterr("Connect() function. " + err_str)
        return status

    def ConnectMultiple(self, con_list):
        """
        In NI-Switch V4.5, cannot find the function. use Connect loop to do this operation.
        ViStatus niSwitch_ConnectMultiple (ViSession vi, ViConstString connectionList);
        con_list: ["r0_c0","r1_c1"]
        """
        global switch_dll
        for con in con_list:
            con = con.split("_")
            status = self.Connect(con[0], con[1])
        return status

    #        con_list = ",".join(con_list)
    #        con_list = con_list.replace("_", "->")
    #        con_str = vitypes.ViString(con_list)
    #        relayAction = vitypes.ViInt32(NISWITCH_VAL_CLOSE_RELAY)
    #        status = switch_dll.niSwitch_ConnectMultiple(self.handler, con_str)
    #        if status != 0:
    #            err_str = self.GetError(status)
    #            print "Error in InstGenMTRX_NI.ConnectMultiple",err_str
    #        return status
    def WaitForCompletion(self, maxtime_ms=5000):
        """
        Pauses until all created paths have settled.
        ViStatus niSwitch_WaitForDebounce (ViSession vi, ViInt32 maximumTime_ms);
        """
        global switch_dll
        max_time = vitypes.ViInt32(maxtime_ms)
        handler = self.__gethandler()
        status = switch_dll.niSwitch_WaitForDebounce(handler, max_time)
        if status != 0:
            err_str = self.GetError(status)
            self.__posterr("WaitForCompletion() function. " + err_str)
        return status

    def DisconnectAll(self):
        """
        ViStatus niSwitch_DisconnectAll (ViSession vi);
        """
        global switch_dll
        handler = self.__gethandler()
        status = switch_dll.niSwitch_DisconnectAll(handler)
        if status != 0:
            err_str = self.GetError(status)
            self.__posterr("DisconnectAll() function. " + err_str)
        return status

    def Close(self):
        """
        ViStatus niSwitch_close (ViSession vi);
        """
        global switch_dll
        # print "Close"
        handler = self.__gethandler()
        status = switch_dll.niSwitch_close(handler)
        if status != 0:
            err_str = self.GetError(status)
            self.__posterr("Close() function. " + err_str)
        self.handler = None
        return status
